import { isObject } from './isType';

/**
 * @group 数据操作
 * 合并对象，并返回新对象
 * @param sourceData 源对象
 * @param target 目标合并对象
 * @param keyTransfor 对象属性转换规则
 * @returns 合并后的新对象
 *
 * @example
 * ```ts
 * const source = { name: 'test', age: 18 };
 * const target = { gender: 'male' };
 * const result = transformKeysAndMerge(source, target);
 * // 结果: { gender: 'male', NAME: 'TEST', AGE: 18 }
 * ```
 */
export const transformKeysAndMerge = (
  sourceData: Record<string, any>,
  target: Record<string, any>,
  keyTransfor = (key: string) => key.toUpperCase()
) => {
  const newProperties: Record<string, any> = {};
  for (let key in sourceData) {
    if (Object.prototype.hasOwnProperty.call(sourceData, key)) {
      newProperties[keyTransfor(key)] = sourceData[key.toUpperCase()];
    }
  }

  return {
    ...target,
    ...newProperties,
  };
};

/**
 * @group 数据操作
 * 将传入对象的所有键名提取为一个字符串数组
 *
 * @param obj 需要提取键名的对象
 * @returns 如果传入的对象是对象类型，则返回该对象的所有键名组成的数组；否则返回一个空数组
 *
 * @example
 * ```ts
 * objectKeys({ name: 'test', age: 18 }) // ['name', 'age']
 * objectKeys(null) // []
 * objectKeys('string') // []
 * ```
 */
export function objectKeys(obj: Record<string, any>): string[] {
  return isObject(obj) ? Object.keys(obj) : [];
}

/**
 * @group 数据操作
 * 将对象中的值转换为数组
 *
 * @param obj 要转换的对象
 * @returns 如果传入的对象非空且是对象类型，则返回其值的数组；否则返回空数组
 *
 * @example
 * ```ts
 * objectValues({ name: 'test', age: 18 }) // ['test', 18]
 * objectValues(null) // []
 * objectValues('string') // []
 * ```
 */
export function objectValues<T = any>(obj: Record<string, T>): T[] {
  return isObject(obj) ? Object.values(obj) : [];
}

/**
 * @group 数据操作
 * 树形结构列表，查找与 field 匹配的数据，返回当前匹配到的数据
 *
 * @param list 查找数据源（树形结构数组）
 * @param field 匹配的字段名，默认为 'value'
 * @param childrenField 子节点字段名，默认为 'children'
 * @param propKey 要查找的值
 * @returns 找到的节点对象，未找到时返回 undefined
 *
 * @example
 * ```ts
 * const treeData = [
 *   { id: 1, name: '父节点1', children: [{ id: 2, name: '子节点1' }] },
 *   { id: 3, name: '父节点2' }
 * ];
 * findItemByTreeList(treeData, 'id', 'children', 2); // { id: 2, name: '子节点1' }
 * findItemByTreeList(treeData, 'id', 'children', 3); // { id: 3, name: '父节点2' }
 * findItemByTreeList(treeData, 'id', 'children', 99); // undefined
 * ```
 */

interface TreeNode<T = any> {
  [key: string]: T | TreeNode<T>[];
}

export const findItemByTreeList = <T extends TreeNode>(
  list: T[] = [],
  field: keyof T = 'value' as keyof T,
  childrenField: keyof T = 'children' as keyof T,
  propKey: T[keyof T]
): T | undefined => {
  for (const item of list) {
    if (item[field] === propKey) return item;
    if (item[childrenField] && Array.isArray(item[childrenField])) {
      const found: any = findItemByTreeList(item[childrenField], field, childrenField, propKey);
      if (found !== undefined) {
        return found;
      }
    }
  }
  return undefined;
};
